/**
 * Created by jinkailong on 2019/3/6.
 */

#include "include/AudioResample.h"
#include "include/AILog.h"


#define SAMPLES 1024

int
AudioResample::initResample(int inChannels, int inSampleRate,
                            int outChannels, int outSampleRate) {
    __android_log_print(ANDROID_LOG_ERROR, "AINative", "%s", "aaaaaaaa");
    if (m_bRunning)
        return 0;
    LOGD("initResample");
    __android_log_print(ANDROID_LOG_ERROR, "AINative", "%s", "bbbbbbbbbb");
    m_bRunning = true;
    int dst_linesize;

    m_nSrcChannels = inChannels;
    m_nSrcSampleRate = inSampleRate;

    m_nDstChannels = outChannels;
    m_nDstSampleRate = outSampleRate;

    swr_ctx = swr_alloc();
    if (!swr_ctx) {
        LOGE("swr_alloc failed");
        return -1;
    }
    int inChannelLayout, outChannelLayout;
    inChannelLayout = m_nSrcChannels == 1 ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
    outChannelLayout = m_nDstChannels == 1 ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;

    av_opt_set_int(swr_ctx, "in_channel_layout", inChannelLayout, 0);
    av_opt_set_int(swr_ctx, "in_sample_rate", m_nSrcSampleRate, 0);
    av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);

    av_opt_set_int(swr_ctx, "out_channel_layout", outChannelLayout, 0);
    av_opt_set_int(swr_ctx, "out_sample_rate", m_nDstSampleRate, 0);
    av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);

    int ret = 0;
    ret = swr_init(swr_ctx);
    if (ret < 0) {
        AVERROR(ret);
        __android_log_print(ANDROID_LOG_ERROR, "AINative", "%s %d", "error", ret);
        goto end;
    }

    int src_linesize;
    ret = av_samples_alloc_array_and_samples(&m_pSrcData, &src_linesize, m_nSrcChannels, SAMPLES,
                                             AV_SAMPLE_FMT_S16, 0);
    if (ret < 0) {
        __android_log_print(ANDROID_LOG_ERROR, "AINative", "%s", "fffffff");
        LOGE("Could not allocate source samples");
        goto end;
    }
    LOGI("swr src buffersize:%d", ret);

    m_nMaxDstNumSamples = av_rescale_rnd(SAMPLES, m_nDstSampleRate, m_nSrcSampleRate,
                                         AV_ROUND_UP);
    ret = av_samples_alloc_array_and_samples(&m_pDstData, &dst_linesize, m_nDstChannels,
                                             m_nMaxDstNumSamples, AV_SAMPLE_FMT_S16,
                                             0);
    LOGI("swr dst buffersize:%d dstSamples:%d", ret, m_nMaxDstNumSamples);

    if (ret < 0) {
        __android_log_print(ANDROID_LOG_ERROR, "AINative", "%s", "zzzzzzzzzzz");
        LOGE("Could not allocate destination samples");
        goto end;
    }

    LOGI("create cycle buffer 1M");
    return ret;

    end:
    m_bRunning = false;
    ret = -1;
    release();
    return ret;
}

void AudioResample::end() {
    LOGD("end resample");
    m_bRunning = false;
    release();
}

void AudioResample::release() {
    if (m_pSrcData)
        av_freep(&m_pSrcData[0]);
    av_freep(&m_pSrcData);

    if (m_pDstData)
        av_freep(&m_pDstData[0]);
    av_freep(&m_pDstData);
    swr_free(&swr_ctx);
}

int8_t *AudioResample::resample(int8_t *buf, int bufLen, int *dst_bufsize) {
    int ret = 0;
    int dst_linesize;

    *dst_bufsize = bufLen;
    memcpy(m_pSrcData[0], buf, sizeof(int8_t) * bufLen);

    LOGD("resample()");
    /* compute destination number of samples */
    int dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, m_nSrcSampleRate) +
                                        SAMPLES, m_nDstSampleRate, m_nSrcSampleRate,
                                        AV_ROUND_UP);
    LOGD("dst samples:%d maxSamples:%d", dst_nb_samples, m_nMaxDstNumSamples);
    if (dst_nb_samples > m_nMaxDstNumSamples) {
        av_freep(&m_pDstData[0]);
        LOGI("dst_nb_samples > m_nMaxDstNumSamples");
        int ret = av_samples_alloc(m_pDstData, &dst_linesize, m_nDstChannels,
                                   dst_nb_samples, AV_SAMPLE_FMT_S16, 1);
        if (ret < 0)
            return buf;
        m_nMaxDstNumSamples = dst_nb_samples;
    }

    LOGD("dst samples:%d", dst_nb_samples);
    /* convert to destination format */
    ret = swr_convert(swr_ctx, m_pDstData, dst_nb_samples, (const uint8_t **) m_pSrcData,
                      SAMPLES);
    if (ret < 0) {
        fprintf(stderr, "Error while converting\n");
        goto end;
    }
    *dst_bufsize = av_samples_get_buffer_size(&dst_linesize, m_nDstChannels,
                                              ret, AV_SAMPLE_FMT_S16, 1);
    if (*dst_bufsize < 0) {
        LOGD("Could not get sample buffer size");
        goto end;
    }
    LOGD("write file dst_bufsize:%d", *dst_bufsize);
    return reinterpret_cast<int8_t *>(m_pDstData[0]);
    end:
    release();
    return buf;
}
